package maModelAnalyser;

import maConfigration.CfgParser;
import maConfigration.MetricSettings;
import maMetrics.MetricCC;
import maMetrics.MetricCPD;
import maMetrics.MetricCountNonConstAttr;
import maMetrics.MetricDIT;
import maMetrics.MetricLOC;
import maMetrics.MetricNOC;
import maMetrics.MetricNOD;
import maMetrics.MetricNumberOfMethods;
import maMetrics.MetricObject;
import maMetrics.MetricsSizeOfStatechart;
import maUtil.LogFile;
import maUtil.RecordUnit;
import maUtil.RecordUnitF;
import maUtil.SortedRecords;
import maUtil.SortedRecordsF;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;

import com.telelogic.rhapsody.core.IRPApplication;
import com.telelogic.rhapsody.core.IRPClass;
import com.telelogic.rhapsody.core.IRPCollection;
import com.telelogic.rhapsody.core.IRPOperation;
import com.telelogic.rhapsody.core.IRPPackage;
import com.telelogic.rhapsody.core.IRPProject;
import com.telelogic.rhapsody.core.RhapsodyAppServer;
import com.telelogic.rhapsody.core.RhapsodyRuntimeException;


/**
 * Redesign the structure: RhapsodyConnector under msModelAnalyser package should not care about
 *  metrics details, it only deal with iterate through package classes and operation. It gets a list
 *   of metrics through CfgPhase under maConfigration. Different metrics should care about all
 *    the details for counting statistics and logging.
 * 
 * */
public class RhapsodyConnector {
	
	private IRPApplication _rhapsodyApp;
	private CfgParser _cfgPhaser; 
	private Collection<MetricObject> _metricList; 
	
	private boolean _rpyStarted = false;
	
	private String _sCurrentPorjName = null;
	private String _sCurrentPkgName = null;
	private String _sCurrentClsName = null;
	
	Collection _projFilter, _pkgFilter, _clsFilter, _opFilter,
			   _projSkipFilter, _pkgSkipFilter, _clsSkipFilter, _projToBeRun = null;
	
	File _fLogPath = null;
	File _fDesPath = null;
	File _fCodePath = null;

	private int _nClsNrProj = 0;
	private float _nProjWeight = 0;
	//weight value for metrics
	private float _nProjWCC = 0;
	private float _nProjWDIT = 0;
	private float _nProjWLOC = 0;
	private float _nProjWNOC = 0;
	private float _nProjWNOD = 0;
	private float _nProjWNOM = 0;
	private float _nProjWNCA = 0;
	private float _nProjWSOS = 0;
	//raw value for metrics
	private int _nProjRCC = 0;
	private int _nProjRDIT = 0;
	private int _nProjRLOC = 0;
	private int _nProjRNOC = 0;
	private int _nProjRNOD = 0;
	private int _nProjRNOM = 0;
	private int _nProjRNCA = 0;
	private int _nProjRSOS = 0;
	private int _nSUMRCC = 0;
	private int _nSUMRDIT = 0;
	private int _nSUMRLOC = 0;
	private int _nSUMRNOC = 0;
	private int _nSUMRNOD = 0;
	private int _nSUMRNOM = 0;
	private int _nSUMRNCA = 0;
	private int _nSUMRSOS = 0;
	
	private int _nProjRedClsCC = 0;
	private int _nProjRedClsDIT = 0;
	private int _nProjRedClsLOC = 0;
	private int _nProjRedClsNOC = 0;
	private int _nProjRedClsNOD = 0;
	private int _nProjRedClsNOM = 0;
	private int _nProjRedClsNCA = 0;
	private int _nProjRedClsSOS = 0;	
	//private int _nProjRawValue = 0;
	
	private long _lTotalRedDebt = 0;
	private long _lTotalYellowDebt = 0;
	
	private SortedRecords _srWeightedClasses = null,//List of top 50 classes got highest weight value
						  _srRedRangeClasses = null,//List of top 50 classes got highest red range count
						  _srTLDIT = null,//Top list of classes which have highest DIT
						  _srTLLOC = null,//Top list of classes which have highest LOC
						  _srTLCC = null,//Top list of classes which have highest CC
						  _srTLNOC = null,//Top list of classes which have highest NOC
						  _srTLNOD = null,//Top list of classes which have highest NOD
						  _srTLNOM = null,//Top list of classes which have highest NOM
						  _srTLNCA = null,//Top list of classes which have highest NCA
						  _srTLSOS = null,//Top list of classes which have highest SOS
						  _srProjMetricsRaw = null,//raw value of metrics in project
						  _srClsNrProj = null;//number of classes in one project
							

	private int _amountInTL = 10;	//number of records in the top list.
	
	private LogFile _lfWeightOfAllClasses = null;
	private LogFile _lfChangeList = null;
	
	private HashMap<String, String> _hmWeightOfAllClesses = null;
	
	public RhapsodyConnector(File logPath, File reportPath, File codePath) {
		_fLogPath = logPath;
		_fDesPath = reportPath;
		_fCodePath = codePath;
		
		
		if(reportPath != null)
			LogFile.setDesPath(reportPath.getAbsolutePath());
		//_rhapsodyApp = RhapsodyAppServer.getActiveRhapsodyApplication();
		_cfgPhaser = new CfgParser(logPath);
		_projToBeRun = _cfgPhaser.getProjectsToBeRun();
		_metricList = _cfgPhaser.getMetricsList();
		_projFilter = _cfgPhaser.getFilter("project"); 
		Iterator itr = _projFilter.iterator();
		while(itr.hasNext()){
			System.out.println(itr.next());
		}
		_pkgFilter = _cfgPhaser.getFilter("package"); 
		_clsFilter = _cfgPhaser.getFilter("class"); 
		_opFilter = _cfgPhaser.getFilter("operation"); 
		_projSkipFilter = _cfgPhaser.getFilter("skipProjIfContains");
		_pkgSkipFilter = _cfgPhaser.getFilter("skipPkgIfContains");
		_clsSkipFilter = _cfgPhaser.getFilter("skipClsIfContains");
		
		openRhapsody(codePath);
		
		_srWeightedClasses = new SortedRecords(50, "List of top 50 classes got highest weight value.");
		_srRedRangeClasses = new SortedRecords(50, "List of top 50 classes got highest red range count.");
		//initiate SortedRecords
		_srTLDIT = new SortedRecords(_amountInTL, "Top DIT in proj");
		_srTLLOC = new SortedRecords(_amountInTL, "Top LOC in proj");
	    _srTLCC = new SortedRecords(_amountInTL, "Top CC in proj");
		_srTLNOC = new SortedRecords(_amountInTL, "Top NOC in proj");
		_srTLNOD = new SortedRecords(_amountInTL, "Top NOD in proj");
		_srTLNOM = new SortedRecords(_amountInTL, "Top NOM in proj");
		_srTLNCA = new SortedRecords(_amountInTL, "Top NCA in proj");
	    _srTLSOS = new SortedRecords(_amountInTL, "Top SOS in proj");
	    _srProjMetricsRaw = new SortedRecords(100, null);
	    _srClsNrProj = new SortedRecords(20, null);
	    
	    _lfChangeList = new LogFile("ChangeListOfAllClasses.csv");
	    //_lfChangeList.logLn("-----------------Changed weight of All Classes Compare to Last Log-----------------");
	    _lfChangeList.logLn("ChangedWeight,ClassName");
	    _lfWeightOfAllClasses = new LogFile("WeightOfAllClasses.csv");
	    //_lfWeightOfAllClasses.logLn("-----------------Weight of All Classes-----------------");
	    _lfWeightOfAllClasses.logLn("ClassName,Weight");
	    SortedRecordsF sr = LogFile.findLatestLogFolder();
	    int le = sr.getSize();
	    if(le > 0)
	    {//find the 
	    	sr.sort();
		    String filePath = sr.getAt(1).getStr() + "\\WeightOfAllClasses.csv";
		    _hmWeightOfAllClesses = LogFile.readCSVFile(new File(filePath));
	    }
	    
	}

	private void openRhapsody(File codePath ) 
	{
		_rpyStarted = false;
		String sPathName = codePath.getAbsolutePath();
		
		try {
			_rhapsodyApp = RhapsodyAppServer.getActiveRhapsodyApplication();
			_rpyStarted = true;
			//break;
		} catch (RhapsodyRuntimeException rre) {
			System.out.println(rre.getMessage());
			if (!_rpyStarted) {
				System.out.println("Starting Rhapsody...");
				_rhapsodyApp = RhapsodyAppServer.createRhapsodyApplication();
			}
			try {
				Thread.sleep(30000);
			} catch (Exception e) {}
		}

		if (_rhapsodyApp != null) 
		{
			IRPProject curprj = _rhapsodyApp.activeProject();
			
			if (curprj == null) {
				System.out.println("No active project, adding...");
				if(_projToBeRun != null && _projToBeRun.isEmpty())
					return;
				Iterator iter = _projToBeRun.iterator();
				while(iter.hasNext())
				{
					String str = (String) iter.next();
					_rhapsodyApp.insertProject(sPathName + str);
					System.out.println("Added " + str);
				}
				System.out.println("Finished adding.");
			}
		}
		else {
			System.out.println("Failed to start Rhapsody");
			
		}
	}
	
	public void closeRhapsody(){
		if (!_rpyStarted) {
			_rhapsodyApp.quit();
			System.out.println("Closing Rhapsody");
		}
	}
	
	public void run()
	{
		IRPCollection projects = _rhapsodyApp.getProjects();
		Iterator compit = projects.toList().iterator();
		float projectValue = 0;
		//summed weight for projects
		SortedRecordsF srPorjWeight = new SortedRecordsF(30, null);
		while (compit != null &&compit.hasNext()) 
		{//for each project, calculate statistics
			boolean proceedWithProj = true;
			IRPProject proj = (IRPProject) compit.next();
			Iterator iterProjSkip = _projSkipFilter.iterator();
			while(iterProjSkip.hasNext()){
				String match = (String) iterProjSkip.next();
				if(proj.getName().contains(match))
				{
					proceedWithProj = false;
				}
			}
			if(!_projFilter.contains(proj.getName()) && proceedWithProj) 
			{
				projectValue = countProj(proj);
				RecordUnitF ru = new RecordUnitF(projectValue, "\"" + proj.getName() + "\"");
				srPorjWeight.addWithoutSort(ru);
			}
			
		}
		//file to log thresholds and weight
		LogFile lfCfg = new LogFile("ConfigurationsAndThresholds.csv");
		lfCfg.logLn("Value,Weight,Threshold,MetricNameAb");
		
		Iterator mList = _metricList.iterator();
		while(mList != null && mList.hasNext())
		{
			MetricObject mo = (MetricObject) mList.next();
			MetricSettings ms = mo.getSettings();
			if(ms != null)
			{//log settings
				lfCfg.logLn(ms.getThresholdGreen() + "," + ms.getWeightGreen() + ",Green," + ms.getNameAb());
				lfCfg.logLn(ms.getThresholdYellow() + "," + ms.getWeightYellow() + ",Yellow," + ms.getNameAb());
				lfCfg.logLn(ms.getThresholdRed() + "," + ms.getWeightRed() + ",Red," + ms.getNameAb());
			}
			mo.finish();// do the finish action
		}
		lfCfg.close();
		
		LogFile logFile = new LogFile("HighestWeightClasses.csv");
		logFile.logLn("Weight,ClassName");
		logFile.log(_srWeightedClasses.getAllStringCSV());
		logFile.close();
		
		logFile = new LogFile("HighestRedRangeClasses.csv");
		logFile.logLn("RedRangeCount,TotalWeight,ClassName");
		logFile.logPln(_srRedRangeClasses.getAllStringCSV());
		logFile.close();
		
		logFile = new LogFile("RawValueForMetrics.csv");
		logFile.logLn("RawValue,MetricName,Project");
		logFile.logPln(_srProjMetricsRaw.getAllStringCSV());
		//add total raw value for metrics
		logFile.logLn(_nSUMRCC + ",CC,TOTAL");
		logFile.logLn(_nSUMRDIT + ",DIT,TOTAL");
		logFile.logLn(_nSUMRLOC + ",LOC,TOTAL");
		logFile.logLn(_nSUMRNOC + ",NOC,TOTAL");
		logFile.logLn(_nSUMRNOD + ",NOD,TOTAL");
		logFile.logLn(_nSUMRNOM + ",NOM,TOTAL");
		logFile.logLn(_nSUMRNCA + ",NVA,TOTAL");
		logFile.logLn(_nSUMRSOS + ",SOS,TOTAL");
		logFile.close();
		
		logFile = new LogFile("NumberOfClassesInProjects.csv");
		logFile.logLn("Number,Project");
		logFile.logPln(_srClsNrProj.getAllStringCSV());
		logFile.close();
		
		logFile = new LogFile("SumProjects.csv");
		logFile.logLn("Value,ProjectName");
		logFile.logPln(srPorjWeight.getAllStringCSV());
		//get all records and calculate the sum for all the projects
		ArrayList<RecordUnitF> rl = srPorjWeight.getAll();
		Iterator<RecordUnitF> it = rl.iterator();
		RecordUnitF ru = null;
		long total = 0;
		while(it.hasNext())
		{
			ru = (RecordUnitF) it.next();
			total += ru.getValue();
		}
		logFile.logLn(total + ",\"TOTAL\"");
		logFile.logLn(_lTotalRedDebt + ",\"TOTALREDDEBT\"");
		logFile.logLn(_lTotalYellowDebt + ",\"TOTALYELLOWDEBT\"");
		logFile.close();
		
		//compare historical data and generate history file
		LogFile.compareHistoricalData();
		
		//delete old log files
		if(_fDesPath != null)
		{
			File f = _fDesPath;
			for (File c : f.listFiles())
				try {
					LogFile.delete(c);
				} catch (IOException e) {
					System.out.println("Failed to delete file under " + _fDesPath);
					e.printStackTrace();
				}
		}
		//code log file to des folder
		copyToDes();
		
	}
	
	
	
	/**
	 * Entrance function
	 * Project level code for count stats
	 * */
	private float countProj(IRPProject proj)
	{//
		if(_metricList.size() < 1)
			return 0;
		//set name
		_sCurrentPorjName = proj.getName();
		//There could be both pkgs and classes under a project
		Iterator packageList = proj.getPackages().toList().iterator();
		IRPPackage pack;
		while (packageList != null &&packageList.hasNext())
		{
			boolean proceedWithPkg = true;
			pack = (IRPPackage) packageList.next();
			Iterator iterPkgSkip = _pkgSkipFilter.iterator();
			while(iterPkgSkip.hasNext()){
				String match = (String) iterPkgSkip.next();
				if(pack.getName().contains(match))
				{
					proceedWithPkg = false;
				}
			}
			if(!_pkgFilter.contains(pack.getName()) && proceedWithPkg)
						countPkg(pack);
		}
		
		Iterator classList = proj.getClasses().toList().iterator();
		IRPClass cls;
		while (classList != null &&classList.hasNext())
		{
			boolean proceedWithCls = true;
			cls = (IRPClass) classList.next();
			Iterator iterClsSkip = _clsSkipFilter.iterator();
			while(iterClsSkip.hasNext()){
				String match = (String) iterClsSkip.next();
				if(cls.getName().contains(match))
				{
					proceedWithCls = false;
				}
			}
			if(_clsFilter.contains(cls.getName()) && proceedWithCls)
				countClass(cls);
		}
		
		SortedRecordsF srProjMetricsW = new SortedRecordsF(30, null);//weight of metrics in project
		
		//
		//log the results for each metric in one projects
		Iterator mList = _metricList.iterator();
		int value = 0;
		int sum = 0;
		while(mList != null && mList.hasNext())
		{
			MetricObject mo = (MetricObject) mList.next();
			if(mo.isApplyToProj()  && !(mo instanceof MetricCPD))
			{//if any metric applies to project
				value = mo.applyInProj(proj);
				sum += value;
				float temp = 0; int nRedSum = 0;
				//add to each metric weight
				if(mo instanceof MetricCC)
				{
					  temp =_nProjWCC;
					  nRedSum = _nProjRedClsCC;
				}
				else if(mo instanceof MetricCountNonConstAttr)	
				{
					temp =_nProjWNCA;
					nRedSum = _nProjRedClsNCA;
				}
				else if(mo instanceof MetricDIT)
				{
					temp =_nProjWDIT;
					nRedSum = _nProjRedClsDIT;
				}
				else if(mo instanceof MetricLOC)	
				{
					temp =_nProjWLOC;
					nRedSum = _nProjRedClsLOC;
				}
				else if(mo instanceof MetricNOC)
				{
					temp =_nProjWNOC;
					nRedSum = _nProjRedClsNOC;
				}
				else if(mo instanceof MetricNOD)
				{
					temp =_nProjWNOD;
					nRedSum = _nProjRedClsNOD;
				}
				else if(mo instanceof MetricNumberOfMethods)
				{
					temp =_nProjWNOM;
					nRedSum = _nProjRedClsNOM;
				}
				else if(mo instanceof MetricsSizeOfStatechart)
				{
					temp =_nProjWSOS;
					nRedSum = _nProjRedClsSOS;
				}
				
				RecordUnitF ru = new RecordUnitF(temp, nRedSum + ",\"" + mo.getName() + "\"," + _sCurrentPorjName);
				srProjMetricsW.addWithoutSort(ru);
				
			}
			
		}
		LogFile logFile = new LogFile("projCSV" + _sCurrentPorjName + ".csv" );
		logFile.logLn("Value,RedNum,MetricName,ProjName");
		logFile.logPln(srProjMetricsW.getAllStringCSV());		
		
		//calculate all the sum for all the metrics in one project
		ArrayList<RecordUnitF> list = srProjMetricsW.getAll();
		Iterator<RecordUnitF> it = list.iterator();
		RecordUnitF ruF = null;
		long total = 0;
		while(it.hasNext())
		{
			ruF = (RecordUnitF) it.next();
			total += ruF.getValue();
		}
		//log total sum
		int nRedSumAll = _nProjRedClsCC + _nProjRedClsNCA + _nProjRedClsDIT + _nProjRedClsLOC
				+ _nProjRedClsNOC + _nProjRedClsNOD + _nProjRedClsNOM + _nProjRedClsSOS;
		logFile.logLn(total + "," + nRedSumAll + ",\"SUM\"," + _sCurrentPorjName);
		logFile.close();
		//log raw values for metrics
		RecordUnit ru = null;
		ru = new RecordUnit(_nProjRCC , "CC," + _sCurrentPorjName);
		_srProjMetricsRaw.addWithoutSort(ru);
		ru = new RecordUnit(_nProjRDIT , "DIT," + _sCurrentPorjName);
		_srProjMetricsRaw.addWithoutSort(ru);
		ru = new RecordUnit(_nProjRLOC , "LOC," + _sCurrentPorjName);
		_srProjMetricsRaw.addWithoutSort(ru);
		ru = new RecordUnit(_nProjRNOC , "NOC," + _sCurrentPorjName);
		_srProjMetricsRaw.addWithoutSort(ru);
		ru = new RecordUnit(_nProjRNOD , "NOD," + _sCurrentPorjName);
		_srProjMetricsRaw.addWithoutSort(ru);
		ru = new RecordUnit(_nProjRNOM , "NOM," + _sCurrentPorjName);
		_srProjMetricsRaw.addWithoutSort(ru);
		ru = new RecordUnit(_nProjRNCA , "NCA," + _sCurrentPorjName);
		_srProjMetricsRaw.addWithoutSort(ru);
		ru = new RecordUnit(_nProjRSOS , "SOS," + _sCurrentPorjName);
		_srProjMetricsRaw.addWithoutSort(ru);
		//add raw value sum
		_nSUMRCC += _nProjRCC;
		_nSUMRDIT += _nProjRDIT;
		_nSUMRLOC += _nProjRLOC;
		_nSUMRNOC += _nProjRNOC;
		_nSUMRNOD += _nProjRNOD;
		_nSUMRNOM += _nProjRNOM;
		_nSUMRNCA += _nProjRNCA;
		_nSUMRSOS += _nProjRSOS;
		
		//logging toplist csv
		LogFile tLLog = new LogFile("metricsTL" + proj.getName() + ".csv");
		tLLog.logLn("Value,Metric,Class");
		tLLog.logPln(_srTLCC.getAllStringCSV());
		tLLog.logPln(_srTLNCA.getAllStringCSV());
		tLLog.logPln(_srTLDIT.getAllStringCSV());
		tLLog.logPln(_srTLLOC.getAllStringCSV());
		tLLog.logPln(_srTLNOC.getAllStringCSV());
		tLLog.logPln(_srTLNOD.getAllStringCSV());
		tLLog.logPln(_srTLNOM.getAllStringCSV());
		tLLog.logPln(_srTLSOS.getAllStringCSV());
		tLLog.close();
		
		_srTLDIT = new SortedRecords(_amountInTL, "Top DIT in proj");
		_srTLLOC = new SortedRecords(_amountInTL, "Top LOC in proj");
	    _srTLCC = new SortedRecords(_amountInTL, "Top CC in proj");
		_srTLNOC = new SortedRecords(_amountInTL, "Top NOC in proj");
		_srTLNOD = new SortedRecords(_amountInTL, "Top NOD in proj");
		_srTLNOM = new SortedRecords(_amountInTL, "Top NOM in proj");
		_srTLNCA = new SortedRecords(_amountInTL, "Top NCA in proj");
	    _srTLSOS = new SortedRecords(_amountInTL, "Top SOS in proj");
		
		_srClsNrProj.add(new RecordUnit(_nClsNrProj ,_sCurrentPorjName));
		//return sum;
		//return weight instead of raw value
		float ret = _nProjWeight;
		
		//reset numbers for project
		_nProjWeight = 0;
		_nProjWCC = 0;
		_nProjWDIT = 0;
		_nProjWLOC = 0;
		_nProjWNOC = 0;
		_nProjWNOD = 0;
		_nProjWNOM = 0;
		_nProjWNCA = 0;
		_nProjWSOS = 0;
		
		_nProjRedClsCC = 0;
		_nProjRedClsDIT = 0;
		_nProjRedClsLOC = 0;
		_nProjRedClsNOC = 0;
		_nProjRedClsNOD = 0;
		_nProjRedClsNOM = 0;
		_nProjRedClsNCA = 0;
		_nProjRedClsSOS = 0;
		
		_nProjRCC = 0;
		_nProjRDIT = 0;
		_nProjRLOC = 0;
		_nProjRNOC = 0;
		_nProjRNOD = 0;
		_nProjRNOM = 0;
		_nProjRNCA = 0;
		_nProjRSOS = 0;
		
		_nClsNrProj = 0;
		
		return ret;
	}
	/**
	 * Package level code for count stats
	 * 
	 * */
	private int countPkg (IRPPackage pkg)
	{//
		if(pkg == null) return 0;
		//set pkg name
		_sCurrentPkgName = pkg.getName();
		//There could be both pkgs and classes under a pkg
		//apply in sub classes first
		Iterator classList = pkg.getClasses().toList().iterator();
		IRPClass cls;
		while (classList != null && classList.hasNext())
		{
			boolean proceedWithCls = true;
			cls = (IRPClass) classList.next();
			Iterator iterClsSkip = _clsSkipFilter.iterator();
			while(iterClsSkip.hasNext()){
				String match = (String)iterClsSkip.next();
				if(cls.getName().contains(match))
				{
					proceedWithCls = false;
				}
			}
			if(!_clsFilter.contains(cls.getName()) && proceedWithCls)
				countClass(cls);
		}
		//then apply in sub packages
		Iterator packageList = pkg.getPackages().toList().iterator();
		IRPPackage pack;
		while (packageList != null &&packageList.hasNext())
		{
			boolean proceedWithPkg = true;
			pack = (IRPPackage) packageList.next();
			Iterator iterPkgSkip = _pkgSkipFilter.iterator();
			while(iterPkgSkip.hasNext()){
				String match = (String)iterPkgSkip.next();
				if(pack.getName().contains(match))
				{
					proceedWithPkg = false;
				}
			}
			if(!_pkgFilter.contains(pack.getName()) && proceedWithPkg)
						countPkg(pack);
		}
		//apply to the pkg itself at last.
		int n = 0;
		int value = 0;
		int valueSum = 0;
		Iterator mList = _metricList.iterator();
		while(mList != null && mList.hasNext())
		{
			MetricObject mo = (MetricObject) mList.next();
			if(mo.isApplyToPkg())
			{//if any metric applies to pkg
				n = mo.applyInPkg(pkg);
				value += n;
				valueSum += value;
			}
			
		}
		return valueSum;
	}
	
	/**
	 * Class level code for count stats
	 * 
	 * */
	private float countClass(IRPClass cls)
	{//
		if(cls == null) return 0;
		_nClsNrProj ++;
		//set cls name 
		_sCurrentClsName = cls.getName();
		Iterator opList = null;
		try{
			opList = cls.getOperations().toList().iterator();
		}
		catch(Exception e)
		{//Can't get operation list
			return 0;
		}
		while(opList != null && opList.hasNext())
		{
			Object op = opList.next();
			IRPOperation operation = (IRPOperation) op;
			if(!_opFilter.contains(operation.getName()))
				countOperation(operation);			
		}
		
		Iterator mList = _metricList.iterator();
		float weight = 0, weightSum = 0;
		int value = 0, redCount = 0;
		while(mList != null && mList.hasNext())
		{//for each metric, calculate weight
			MetricObject mo = (MetricObject) mList.next();
			if(mo.isApplyToCls())
			{//if any metric applies to class, apply in calss
				value = mo.applyInCls(cls);
			}
			weight = mo.getWeightedValue(value);
			weightSum += weight;
			
			if(weight > 0)
			{
				boolean isRed = (3 == mo.getRange(value));
				if(isRed) 
				{//if the value is in red range
					//add to total debt sum
					_lTotalRedDebt += weight;
					redCount++;
				}
				else if(2 == mo.getRange(value))
				{//if the value is in yellow range
					_lTotalYellowDebt += weight;
				}
				
				//for each metric, log top classes and sum weight for project
				if(mo instanceof MetricCC)
				{
					  _srTLCC.add(new RecordUnit(value, "CC,"+cls.getName()));
					  _nProjWCC += weight;
					  _nProjRCC += value;
					  if(isRed) _nProjRedClsCC++;
				}
				else if(mo instanceof MetricCountNonConstAttr)	
				{
					  _srTLNCA.add(new RecordUnit(value, "NCA,"+cls.getName()));
					  _nProjWNCA += weight;
					  _nProjRNCA += value;
					  if(isRed) _nProjRedClsNCA++;
				}
				else if(mo instanceof MetricDIT)
				{
					  _srTLDIT.add(new RecordUnit(value, "DIT,"+cls.getName()));
					  _nProjWDIT += weight;
					  _nProjRDIT += value;
					  if(isRed) _nProjRedClsDIT++;
				}
				else if(mo instanceof MetricLOC)	
				{
					  _srTLLOC.add(new RecordUnit(value, "LOC,"+cls.getName()));
					  _nProjWLOC += weight;
					  _nProjRLOC += value;
					  if(isRed) _nProjRedClsLOC++;
				}
				else if(mo instanceof MetricNOC)
				{
					  _srTLNOC.add(new RecordUnit(value, "NOC,"+cls.getName()));
					  _nProjWNOC += weight;
					  _nProjRNOC += value;
					  if(isRed) _nProjRedClsNOC++;
				}
				else if(mo instanceof MetricNOD)
				{
					  _srTLNOD.add(new RecordUnit(value, "NOD,"+cls.getName()));
					  _nProjWNOD += weight;
					  _nProjRNOD += value;
					  if(isRed) _nProjRedClsNOD++;
				}
				else if(mo instanceof MetricNumberOfMethods)
				{
					  _srTLNOM.add(new RecordUnit(value, "NOM,"+cls.getName()));
					  _nProjWNOM += weight;
					  _nProjRNOM += value;
					  if(isRed) _nProjRedClsNOM++;
				}
				else if(mo instanceof MetricsSizeOfStatechart)
				{
					  _srTLSOS.add(new RecordUnit(value, "SOS,"+cls.getName()));
					  _nProjWSOS += weight;
					  _nProjRSOS += value;
					  if(isRed) _nProjRedClsSOS++;
				}
			}
			
			
		}
		
		String fullClassName = cls.getName() + ":" + _sCurrentPkgName + ":" + _sCurrentPorjName;
		if(weightSum > 0)
		{//if the weight sum of the project is bigger than 0
			if(_srWeightedClasses.notFull())
			{
				RecordUnit ru = new RecordUnit((int) weightSum, fullClassName);
				_srWeightedClasses.addWithoutSort(ru);
			}
			else if(weightSum > _srWeightedClasses.getMinValue())
			{
				RecordUnit ru = new RecordUnit((int) weightSum, fullClassName);
				_srWeightedClasses.add(ru);
			}
			//log to the weight of all classes list
			_lfWeightOfAllClasses.logLn( fullClassName + "," + weightSum);
			//add to project sum
			_nProjWeight += weightSum;	
		}
		
		if(redCount > 0)
		{//if the class got one or more metrics located in the red range
			if(_srRedRangeClasses.notFull())
			{
				RecordUnit ru = new RecordUnit(redCount, weightSum + "," + fullClassName);
				_srRedRangeClasses.addWithoutSort(ru);
			}
			else if(redCount > _srRedRangeClasses.getMinValue())
			{
				RecordUnit ru = new RecordUnit(redCount, weightSum + "," + fullClassName);
				_srRedRangeClasses.add(ru);
			}
		}
		
		//compare to the weight of last run
		String sOldWeight = _hmWeightOfAllClesses.get(fullClassName);
		if(sOldWeight != null && sOldWeight != "")
		{
			int nOldWeight = (int) Float.valueOf(sOldWeight.trim()).floatValue();
			if(weightSum != nOldWeight)
			{//log if any difference
				_lfChangeList.logLn((weightSum - nOldWeight) + " , " + fullClassName);
			}
		}
		else if(weightSum > 0)
		{//if could not find old record and weight is bigger than 0, 
			//we assume that this is a new class, log it
			_lfChangeList.logLn((weightSum) + " , " + fullClassName);
		}
		
		return weightSum;
	}
	
	/**
	 * Operation level code for count stats
	 * */
	private int countOperation(IRPOperation op)
	{
		Iterator mListOp = _metricList.iterator();
		int value = 0;
		int valueSum = 0;
		while(mListOp != null && mListOp.hasNext())
		{
			MetricObject moOp = (MetricObject) mListOp.next();
			if(moOp.isApplyToOp())
			{//if any metric applies to operation
				value = moOp.applyInOp(op);
				valueSum += value;
			}
		}
		return valueSum;
	}
	
	private void copyToDes()
	{//copy log files
		if(_fDesPath != null)
		{
			String str = LogFile.getPath();
			String str1 = _fDesPath.getPath() + "\\" + LogFile.getFolderName();

			File source = new File(str);
			File desc = new File(str1);
			try {
			    LogFile.copyDirectory(source, desc);
			} catch (IOException e) {
				System.out.println("Failed to copy file to " + _fDesPath);
			    e.printStackTrace();
			}
			CfgParser.writeFolderName(_fDesPath.getPath() + "\\FolderList.csv");
		}
	}




}
